package org.tri.gui.view;

import furbelow.SpinningDial;
import furbelow.WaitIndicator;
import java.awt.Component;
import java.awt.Font;
import java.util.concurrent.ExecutionException;
import javax.swing.JOptionPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableColumnModel;
import org.tri.entity.Animal;
import org.tri.entity.Establecimiento;
import org.tri.gui.worker.AnimalListFillWorker;
import org.tri.gui.worker.PersistenceWorker;
import org.tri.gui.worker.TableFillListener;
import org.tri.gui.worker.retrievers.BusquedaDataRetriever;
import org.tri.model.AnimalesListTableModel;
import org.tri.persistence.search.BusquedaAnimal;

/*
 * El dialog {@code AnimalesListView} permite visualizar los animales 
 * que actualmente se encuentran en un establecimiento, incluyendo animales
 * muertos si es requerido, e incluso animales vendidos, por si es necesario.
 * Esta vista también permite cambiar el estado de un animal, en el caso de 
 * que alguno muera.
 * @author kiira.
 * @version 1.0, Apr 7, 2012
 */
public class AnimalesListView extends javax.swing.JDialog implements 
        TableFillListener {

    /** Establecimiento del cual obtener los animales. */
    private Establecimiento establecimiento;
    /** Model que contendra los animales mostrados. */
    private AnimalesListTableModel animalesModel;
    /** Indicador para marcar el panel como en espera. */
    private WaitIndicator waitIndicator;
    /** Animación que indica que el panel esta en espera. */
    private SpinningDial loadingIcon;
    
    /**
     * Crea una nueva vista, mostrando los animales para el establecimiento
     * inidicado.
     * @param parent componente padre de este dialog.
     * @param establecimiento establecimiento del cual mostrar los animales.
     */
    public AnimalesListView( java.awt.Frame parent, 
                             Establecimiento establecimiento ) {
        super(parent, true);
        
        //seteamos el establecimiento
        this.establecimiento = establecimiento;
               
        //creamos el table model
        animalesModel = new AnimalesListTableModel( 3 );
        
        initComponents();        
        
        //alineamos el componente
        setLocationRelativeTo( parent );
        
        //asignamos el nombre del establecimiento
        jLTituloEstablecimiento.setText( establecimiento.getNombre() );
        
        //creamos el waitIcon
        loadingIcon = new SpinningDial( 20, 20, 10 );
        
        //cargamos la tabla
        fillAnimalTable();
        
    }//end constructor

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {
        java.awt.GridBagConstraints gridBagConstraints;

        jPUMAnimal = new javax.swing.JPopupMenu();
        jMICambiarEstado = new javax.swing.JMenuItem();
        filler3 = new javax.swing.Box.Filler(new java.awt.Dimension(10, 0), new java.awt.Dimension(10, 0), new java.awt.Dimension(10, 32767));
        filler4 = new javax.swing.Box.Filler(new java.awt.Dimension(10, 0), new java.awt.Dimension(10, 0), new java.awt.Dimension(10, 32767));
        filler5 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 10), new java.awt.Dimension(0, 10), new java.awt.Dimension(32767, 10));
        filler6 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 10), new java.awt.Dimension(0, 10), new java.awt.Dimension(32767, 10));
        jPCentral = new javax.swing.JPanel();
        jPHeader = new javax.swing.JPanel();
        jLTituloExplain = new javax.swing.JLabel();
        jLTituloEstablecimiento = new javax.swing.JLabel();
        filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 5), new java.awt.Dimension(0, 5), new java.awt.Dimension(32767, 5));
        jLBusqueda = new javax.swing.JLabel();
        jTFBusqueda = new javax.swing.JTextField();
        jBBusqueda = new javax.swing.JButton();
        jLWaitIcon = new javax.swing.JLabel();
        filler8 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 5), new java.awt.Dimension(0, 5), new java.awt.Dimension(32767, 5));
        jLIncluir = new javax.swing.JLabel();
        jCBMuertos = new javax.swing.JCheckBox();
        jCBVendidos = new javax.swing.JCheckBox();
        filler2 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 5), new java.awt.Dimension(0, 5), new java.awt.Dimension(32767, 5));
        jSPAnimalesTable = new javax.swing.JScrollPane();
        jTAnimales = new javax.swing.JTable();
        jBCerrar = new javax.swing.JButton();

        jMICambiarEstado.setText("Cambiar estado");
        jMICambiarEstado.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMICambiarEstadoActionPerformed(evt);
            }
        });
        jPUMAnimal.add(jMICambiarEstado);

        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
        getContentPane().add(filler3, java.awt.BorderLayout.WEST);
        getContentPane().add(filler4, java.awt.BorderLayout.EAST);
        getContentPane().add(filler5, java.awt.BorderLayout.NORTH);
        getContentPane().add(filler6, java.awt.BorderLayout.SOUTH);

        jPCentral.setLayout(new java.awt.GridBagLayout());

        jPHeader.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.CENTER, 0, 0));

        jLTituloExplain.setFont(org.tri.gui.view.ViewConstants.defaultLabelFont.deriveFont( Font.PLAIN, 24 ));
        jLTituloExplain.setText("Animales de ");
        jPHeader.add(jLTituloExplain);

        jLTituloEstablecimiento.setFont(org.tri.gui.view.ViewConstants.defaultLabelFont.deriveFont( Font.BOLD, 24 ));
        jPHeader.add(jLTituloEstablecimiento);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridwidth = 4;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START;
        jPCentral.add(jPHeader, gridBagConstraints);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.gridwidth = 7;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        jPCentral.add(filler1, gridBagConstraints);

        jLBusqueda.setText("Ingrese la caravana a buscar: ");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 2;
        jPCentral.add(jLBusqueda, gridBagConstraints);

        jTFBusqueda.setColumns(15);
        jTFBusqueda.setMinimumSize(new java.awt.Dimension(175, 25));
        jTFBusqueda.setNextFocusableComponent(jBBusqueda);
        jTFBusqueda.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jBBusquedaActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.gridwidth = 3;
        jPCentral.add(jTFBusqueda, gridBagConstraints);

        jBBusqueda.setText("Buscar");
        jBBusqueda.setNextFocusableComponent(jCBMuertos);
        jBBusqueda.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jBBusquedaActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 4;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.insets = new java.awt.Insets(0, 5, 0, 0);
        jPCentral.add(jBBusqueda, gridBagConstraints);

        jLWaitIcon.setMinimumSize(new java.awt.Dimension(20, 20));
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 5;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.insets = new java.awt.Insets(0, 5, 0, 0);
        jPCentral.add(jLWaitIcon, gridBagConstraints);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 3;
        gridBagConstraints.gridwidth = 7;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        jPCentral.add(filler8, gridBagConstraints);

        jLIncluir.setText("Incluir: ");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 4;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_END;
        jPCentral.add(jLIncluir, gridBagConstraints);

        jCBMuertos.setText("Muertos");
        jCBMuertos.setNextFocusableComponent(jCBVendidos);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 4;
        jPCentral.add(jCBMuertos, gridBagConstraints);

        jCBVendidos.setText("Vendidos");
        jCBVendidos.setNextFocusableComponent(jBCerrar);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 2;
        gridBagConstraints.gridy = 4;
        jPCentral.add(jCBVendidos, gridBagConstraints);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 5;
        gridBagConstraints.gridwidth = 7;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        jPCentral.add(filler2, gridBagConstraints);

        jSPAnimalesTable.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);

        jTAnimales.setModel(animalesModel);
        jTAnimales.setCellSelectionEnabled(true);
        jTAnimales.setComponentPopupMenu(jPUMAnimal);
        jTAnimales.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
        jTAnimales.setShowHorizontalLines(false);
        jTAnimales.setShowVerticalLines(false);
        jTAnimales.setTableHeader(null);
        jTAnimales.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mousePressed(java.awt.event.MouseEvent evt) {
                jTAnimalesMousePressed(evt);
            }
            public void mouseReleased(java.awt.event.MouseEvent evt) {
                jTAnimalesMouseReleased(evt);
            }
        });
        jSPAnimalesTable.setViewportView(jTAnimales);
        TableColumnModel columnModel = jTAnimales.getColumnModel();
        DefaultTableCellRenderer renderer = new AnimalCellRenderer();
        for ( int i = 0; i < columnModel.getColumnCount() ; i++ )
        columnModel.getColumn( i ).setCellRenderer( renderer );

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 6;
        gridBagConstraints.gridwidth = 7;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.weighty = 1.0;
        jPCentral.add(jSPAnimalesTable, gridBagConstraints);

        jBCerrar.setText("Cerrar");
        jBCerrar.setNextFocusableComponent(jTFBusqueda);
        jBCerrar.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jBCerrarActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 6;
        gridBagConstraints.gridy = 7;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_END;
        gridBagConstraints.insets = new java.awt.Insets(5, 0, 0, 0);
        jPCentral.add(jBCerrar, gridBagConstraints);

        getContentPane().add(jPCentral, java.awt.BorderLayout.CENTER);

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void jBCerrarActionPerformed( java.awt.event.ActionEvent evt ) {//GEN-FIRST:event_jBCerrarActionPerformed
        //disposeamos la ventana
        this.dispose();
        
    }//GEN-LAST:event_jBCerrarActionPerformed

    private void jMICambiarEstadoActionPerformed( java.awt.event.ActionEvent evt ) {//GEN-FIRST:event_jMICambiarEstadoActionPerformed
        //obtenemos las coordenadas de la celda seleccionada
        int row = jTAnimales.getSelectedRow();
        int column = jTAnimales.getSelectedColumn();
        
        //obtenemnos el animal
        Animal animal = (Animal)animalesModel.getValueAt( row, column );
        
        //si no es un animal, obviamos el click
        if ( animal == null ) {
            //pass
          
        //puede que el animal este vendido, en ese caso no se puede marcar
        } else if ( animal.isViva() && animal.obtenerVentaActual() != null ) {
             JOptionPane.showMessageDialog( 
                    this, "No puede marcar un animal vendido como muerto.", 
                    "Acción no permitida", JOptionPane.INFORMATION_MESSAGE );
        
        } else {
            //cambiamos el estado del animal
            animal.setViva( !animal.isViva() );
            
            //generamos el worker para persistirlo
            ( new PersistenceWorker( animal ) ).execute();
                   
            //updateamos la celda de la tabla
            animalesModel.fireTableCellUpdated( row, column );
            
        }//end if                                   
        
    }//GEN-LAST:event_jMICambiarEstadoActionPerformed

    private void jTAnimalesMouseReleased( java.awt.event.MouseEvent evt ) {//GEN-FIRST:event_jTAnimalesMouseReleased
        //seleccionamos la celda bajo el mouse
        if ( SwingUtilities.isRightMouseButton( evt ) )
            jTAnimales.changeSelection( jTAnimales.rowAtPoint( evt.getPoint() ),
                                        jTAnimales.columnAtPoint( evt.getPoint() ),
                                        false, false );
        
    }//GEN-LAST:event_jTAnimalesMouseReleased

    private void jBBusquedaActionPerformed( java.awt.event.ActionEvent evt ) {//GEN-FIRST:event_jBBusquedaActionPerformed
        //llenamos la tabla con los valores de la busqueda
        fillAnimalTable();
        
    }//GEN-LAST:event_jBBusquedaActionPerformed

    private void jTAnimalesMousePressed( java.awt.event.MouseEvent evt ) {//GEN-FIRST:event_jTAnimalesMousePressed
        jTAnimalesMouseReleased( evt );
        
    }//GEN-LAST:event_jTAnimalesMousePressed

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.Box.Filler filler1;
    private javax.swing.Box.Filler filler2;
    private javax.swing.Box.Filler filler3;
    private javax.swing.Box.Filler filler4;
    private javax.swing.Box.Filler filler5;
    private javax.swing.Box.Filler filler6;
    private javax.swing.Box.Filler filler8;
    private javax.swing.JButton jBBusqueda;
    private javax.swing.JButton jBCerrar;
    private javax.swing.JCheckBox jCBMuertos;
    private javax.swing.JCheckBox jCBVendidos;
    private javax.swing.JLabel jLBusqueda;
    private javax.swing.JLabel jLIncluir;
    private javax.swing.JLabel jLTituloEstablecimiento;
    private javax.swing.JLabel jLTituloExplain;
    private javax.swing.JLabel jLWaitIcon;
    private javax.swing.JMenuItem jMICambiarEstado;
    private javax.swing.JPanel jPCentral;
    private javax.swing.JPanel jPHeader;
    private javax.swing.JPopupMenu jPUMAnimal;
    private javax.swing.JScrollPane jSPAnimalesTable;
    private javax.swing.JTable jTAnimales;
    private javax.swing.JTextField jTFBusqueda;
    // End of variables declaration//GEN-END:variables
    
    /**
     * Eventos para indicar que el panel se encuentra actualmente ocupado 
     * realizando una tarea de busqueda.
     * @param inicia indica si se debe iniciar o terminar los efectos graficos.
     * <li>true inician los efectos de espera. <li>false terminan los efectos
     * de espera.
     */
    private void fireWaitTrigger( boolean inicia ) {                
        if ( inicia ) {
            jPCentral.requestFocus();
            waitIndicator = new WaitIndicator( jPCentral );
            jLWaitIcon.setIcon( loadingIcon );
            
        } else {
            jTFBusqueda.requestFocus();
            waitIndicator.dispose();  
            jLWaitIcon.setIcon( null );
            
        }
        
    }//end método fireWaitTrigger
    
    /**
     * Llena el modelo de la tabla de animales con animales segun corresponda
     * por la busqueda realizada.
     */
    private void fillAnimalTable() {
        //armamos la busqueda para los animales
        BusquedaAnimal busqueda = new BusquedaAnimal();
        busqueda.porEstablecimiento( establecimiento );
        busqueda.porCaravana( jTFBusqueda.getText() );        
        busqueda.ordenarPor( "caravana", false );
        
        //restricciones segun la opción de subgrupo
        if ( !jCBMuertos.isSelected() )
            busqueda.porViva( true );
        
        if ( !jCBVendidos.isSelected() )
            busqueda.porVendido( false );
        
        //creamos un worker para buscar animales para el modelo
        AnimalListFillWorker worker = new AnimalListFillWorker( animalesModel, 
                new BusquedaDataRetriever<Animal>( busqueda ) );
        
        worker.addTableFillListener( this );
        
        fireWaitTrigger( true );
        
        worker.execute();                
        
    }//end método fillAnimalTable
    
    /**
     * {@inheritDoc}
     */
    @Override
    public void doneFillingTable() {
        fireWaitTrigger( false );
        
    }//end método doneFillingTable

    /**
     * {@inheritDoc}
     */
    @Override
    public void errorFillingTable( ExecutionException ex ) {
        //mostrar error
        
    }//end método errorFillingTable
    
    /**
     * Renderer privado para la tabla de animales. Lo unico que hace es agregar
     * un indicador entre parentesis para indicar el estado del animal.
     */
    private class AnimalCellRenderer extends DefaultTableCellRenderer {

        /**
         * {@inheritDoc}
         */
        @Override
        public Component getTableCellRendererComponent( JTable table,
                                                        Object value,
                                                        boolean isSelected,
                                                        boolean hasFocus,
                                                        int row, int column ) {
            //solo realiza procesamiento si hay valor
            if ( value != null ) {
                //variable para contener el tag segun el estado del animal
                String tag = "";
                
                //casteamos a animal
                Animal animal = (Animal)value;              
                                
                //agregamos el "muerto" o "vendido" luego del número de caravana.
                if ( !animal.isViva() )
                    tag = " (muerto)";
                else if ( animal.getVenta() != null )
                    tag = " (vendido)";
                
                value = String.format( "%s%s", animal, tag );

            }//end if
            
            return super.getTableCellRendererComponent( table, value, isSelected,
                                                                      hasFocus, 
                                                                      row, 
                                                                      column );
            
        }//end método getTableCellRendererComponent
                
    }//end clase AnimalCellRenderer

}//end dialog AnimalesListView
